// 保证一个类仅有一个实例，并提供一个访问它的全局访问点，一般购物车、登录等都是一个单例。
{
  // 代码示例
  // es6
  class SingleManage {
    constructor({ name, level }) {
      if (!SingleManage.instance) {
        this.name = name;
        this.level = level;
        SingleManage.instance = this;
      }
      return SingleManage.instance;
    }
  }

  let boss = new SingleManage({ name: 'Jokul', level: '1' });
  let boss2 = new SingleManage({ name: 'Jokul2', level: '2' });
  console.log(boss === boss2);

  // es5
  function SingleManage(manage) {
    this.name = manage.name;
    this.level = manage.level;
    this.info = function () {
      console.warn(
        "Boss's name is " + this.name + ' and level is ' + this.level
      );
    };
  }
  SingleManage.getInstance = function (manage) {
    if (!this.instance) {
      this.instance = new SingleManage(manage);
    }
    return this.instance;
  };
  var boss = SingleManage.getInstance({ name: 'Jokul', level: '1' });
  var boss2 = SingleManage.getInstance({ name: 'Jokul2', level: '2' });
  boss.info();
  boss2.info();
}

{
  // 应用实例
  // 实现一个storage
  // 先实现一个基础的StorageBase类，把getItem和setItem方法放在它的原型链上
  function StorageBase() {}
  StorageBase.prototype.getItem = function (key) {
    return localStorage.getItem(key);
  };
  StorageBase.prototype.setItem = function (key, value) {
    return localStorage.setItem(key, value);
  };

  // 以闭包的形式创建一个引用自由变量的构造函数
  const Storage = (function () {
    let instance = null;
    return function () {
      // 判断自由变量是否为null
      if (!instance) {
        // 如果为null则new出唯一实例
        instance = new StorageBase();
      }
      return instance;
    };
  })();

  // 这里其实不用 new Storage 的形式调用，直接 Storage() 也会有一样的效果
  const storage1 = new Storage();
  const storage2 = new Storage();

  storage1.setItem('name', 'yd');
  // yd
  storage1.getItem('name');
  // 也是yd
  storage2.getItem('name');

  // 返回true
  storage1 === storage2;
}
